/*
 Copyright 2008 Under Dusken

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at

         http://www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
 */

package org.dyndns.anderlin.jmplayer.service.impl;


import org.apache.log4j.Logger;
import org.dyndns.anderlin.jmplayer.dao.GenericDao;
import org.dyndns.anderlin.jmplayer.model.JmplayerObject;
import org.dyndns.anderlin.jmplayer.service.GenericService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.support.DataAccessUtils;
import org.springframework.util.Assert;

import java.util.List;

public class GenericServiceImpl<T extends JmplayerObject> implements
        GenericService<T> {

    protected GenericDao genericDao;

    protected Class<T> type;

    protected static final Logger log = Logger.getLogger(GenericServiceImpl.class);

    public GenericServiceImpl(Class<T> type) {
        Assert.notNull(type, "The type of the generic service may not be null");
        this.type = type;
    }

    public T getEntity(Long ID) {
        if (ID == null) {
            return null;
        }
        T entity = null;
        try {
            entity = genericDao.getByID(type, ID);
        } catch (DataAccessException dae) {
            log.warn(
                    "Unable to get " + type.getSimpleName() + " with ID " + ID,
                    dae);
        }
        if (entity == null) {
            log.info(
                    "Unable to get " + type.getSimpleName() + " with ID " + ID + ", it might not exist!");
        }
        return entity;
    }

    public T getEntityReference(Long ID) {
        if (ID == null) {
            return null;
        }
        T entity = null;
        try {
            entity = genericDao.getReference(type, ID);
        } catch (DataAccessException dae) {
            log.warn("Unable to get reference to" + type.getSimpleName()
                    + " with ID " + ID, dae);
        }
        return entity;
    }

    public T getEntityByExternalID(Long ID) {
        if (ID == null) {
            return null;
        }
        T entity = null;
        try {
            List<T> entities = genericDao.getByQuery("select c from "
                    + type.getSimpleName() + " c where c.externalID = " + ID,
                    null);
            if (entities.size() > 1) {
                log.warn(new StringBuilder().append("More than one ").append(
                        type.getSimpleName()).append(" shares externalID ")
                        .append(ID).toString());
                if (log.isInfoEnabled())
                    log.info(entities);
            }
            entity = (T) DataAccessUtils.uniqueResult(entities);
        } catch (DataAccessException dae) {
            log.warn("Unable to get " + type.getSimpleName()
                    + " with externalID " + ID, dae);
        }
        return entity;
    }

    public T saveOrUpdate(T entity) {
        if (log.isDebugEnabled())
            log.debug(entity);
        try {
            return genericDao.saveOrUpdate(entity);
        } catch (DataAccessException e) {
            log.warn("Unable to persist entity " + entity.toString()
                    + " with id=" + entity.getID(), e);
            return null;
        }
    }

    public boolean remove(T entity) {
        boolean returned = false;
        try {
            genericDao.remove(entity);
            returned = true;
        } catch (DataAccessException e) {
            log.warn("Unable to remove entity " + entity.toString()
                    + " with id=" + entity.getID(), e);
        }
        return returned;
    }

    @Autowired
    @Required
    public void setGenericDao(GenericDao genericDao) {
        this.genericDao = genericDao;
    }
}